<template>
    <div style="width: 500px; height: 500px;margin-left: auto;margin-right: auto;margin-top: 200px;">
        <!-- 文件选择输入框，绑定文件变化事件 -->
        <el-button type="primary" @click="triggerFileInput">选择文件</el-button>
        <!-- 隐藏的文件输入框 -->
        <input type="file" ref="fileInput" @change="handleFileChange" style="display: none" />

        <!-- 上传文件按钮，绑定点击事件 -->
        <el-button @click="startUpload" :disabled="isUploading">上传文件</el-button>

        <!-- 显示上传进度的进度条 -->
        <el-progress style="margin-top: 30px;" :percentage="progress"></el-progress>

        <!-- 显示文件路径的链接 -->
        <div v-if="fileUrl">文件路径: <a :href="fileUrl" target="_blank">{{ fileUrl }}</a></div>

        <!-- 显示上传消息 -->
        <div v-if="uploadMessage">{{ uploadMessage }}</div>
    </div>
</template>

<script setup lang='ts'>
import { onMounted, reactive, ref } from 'vue';
import {
    S3Client,
    CreateMultipartUploadCommand,
    UploadPartCommand,
    CompleteMultipartUploadCommand,
    ListPartsCommand
} from '@aws-sdk/client-s3';

// 响应式变量
const fileInput = ref(null);
const file = ref(null);
const chunks = ref([]);
const uploadedChunks = ref([]);
const progress = ref(0);
const wname = ref(null);
const uploadMessage = ref('');
const isUploading = ref(false);
const fileUrl = ref('');
const uploadedPartNumbers = ref([]);

// 获取S3客户端实例
const s3Client = new S3Client({
    endpoint: 'http://api.oss.boadan.com',
    s3ForcePathStyle: true,
    signatureVersion: 'v4',
    region: 'us-east-1',
    forcePathStyle: true,
    credentials: {
        accessKeyId: 'Cu98UEmAXLN0wzwZxRbG',
        secretAccessKey: 'S3M00eZKB7CseJZly4SOtgGr06NNUMTQdutE5AP3'
    }
});

// 文件选择变化时触发的函数
const triggerFileInput = () => {
    fileInput.value.click();
};

// 分片函数，用于将一个大文件切割成多个较小的数据块
const createChunks = (File: File, partSize = 5 * 1024 * 1024): Blob[] => {
    const chunks: Blob[] = [];
    let offset = 0;
    // 只要当前偏移量小于文件大小，就持续分片
    while (offset < File.size) {
        // 计算本次分片的结束位置，取当前偏移量加上分片大小与文件大小的最小值，防止超出文件边界
        const end = Math.min(offset + partSize, File.size);
        // 使用File.slice方法从文件中截取从偏移量到结束位置的片段，添加到分块数组中
        chunks.push(File.slice(offset, end));
        // 更新偏移量，为下一次分片做准备
        offset += partSize;
        console.log(end)
    }
    return chunks;
}

// 隐藏输入框
const handleFileChange = (e: any) => {
    const selectedFile = e.target.files?.[0];
    if (selectedFile) {
        file.value = selectedFile;
        console.log("文件大小:", selectedFile.size);
        chunks.value = createChunks(selectedFile);
    }
    wname.value = selectedFile?.name;
    console.log(selectedFile);
};

// // 上传
// const startUpload = async () => {
//     const etags: string[] = [];
//     if (!file.value) {
//         uploadMessage.value = '请先选择文件';
//         return;
//     }
//     isUploading.value = true;
//     uploadMessage.value = '上传中，请稍候...';
//     const bucket = 'fuluojia';
//     const key = `uploads/${file.value.name}`;
//     const partSize = 5 * 1024 * 1024;
//     let uploadId: string;
//     try {
//         //如果本地里没有，初始化id
//         if (localStorage.getItem(file.value.name) == null) {
//             const params = {
//                 Bucket: bucket,
//                 Key: key,
//                 ContentType: file.value.type
//             };
//             const createMultipartUploadResponse = await s3Client.send(new CreateMultipartUploadCommand(params));
//             uploadId = createMultipartUploadResponse.UploadId;
//             //初始化
//             localStorage.setItem(file.value.name, uploadId);
//         } else {
//             // 检查已上传的部分,
//             uploadId = localStorage.getItem(file.value.name) as string;
//             const listPartsResponse = await s3Client.send(new ListPartsCommand({
//                 Bucket: bucket,
//                 Key: key,
//                 UploadId: uploadId
//             }));
//             const uploadedParts = listPartsResponse.Parts || [];
//             uploadedChunks.value.push(uploadedParts.partNumber);
//             console.log(uploadedParts)
//             uploadedParts.forEach((part) => {
//                 // console.log(part.ETag);
//                 // console.log(part.PartNumber);
//                 etags.push(part.ETag);
//                 uploadedChunks.value.push(part.PartNumber);
//             });
//             console.log(uploadedChunks.value);
//             console.log(uploadedParts);
//         }

//         let totalUploaded = 0;

//         for (let i = 0; i < chunks.value.length; i++) {
//             const partNumber = i + 1;
//             if (uploadedPartNumbers.value.includes(partNumber)) {
//                 const chunk = chunks.value[i];
//                 totalUploaded += chunk.size;
//                 continue;
//             }
//             const chunk = chunks.value[i];
//             const response = await s3Client.send(new UploadPartCommand({
//                 Bucket: bucket,
//                 Key: key,
//                 UploadId: uploadId,
//                 PartNumber: partNumber,
//                 Body: chunk
//             }));
//             console.log(response);
//             console.log(response.ETag);
//             etags.push(response.ETag);
//             uploadedChunks.value.push(partNumber);
//             totalUploaded += chunk.size;
//             progress.value = (totalUploaded / file.value.size) * 100;
//         }

//         // 合并
//         // if (etags.length !== uploadedChunks.value.length) {
//         //     throw new Error('ETag数组和已上传分片编号数组长度不一致');
//         // }
//         await s3Client.send(new CompleteMultipartUploadCommand({
//             Bucket: bucket,
//             Key: key,
//             UploadId: uploadId,
//             MultipartUpload: {
//                 Parts: uploadedChunks.value.map((partNumber, index) => ({
//                     ETag: etags[index],
//                     PartNumber: partNumber
//                 }))
//             }
//         }));
//         localStorage.removeItem(file.value.name)
//         fileUrl.value = `http://api.oss.boadan.com/${bucket}/${key}`;
//         uploadMessage.value = '文件上传成功';
//     } catch (error) {
//         uploadMessage.value = '文件上传失败';
//         console.error(error);
//     } finally {
//         isUploading.value = false;
//     }
// };

const startUpload = async () => {
    if (!file.value) {
        uploadMessage.value = '请先选择文件';
        return;
    }

    isUploading.value = true;
    uploadMessage.value = '上传中，请稍候...';
    const bucket = 'fuluojia';
    const key = `uploads/${file.value.name}`;
    const partSize = 5 * 1024 * 1024;  // 分片大小5MB
    const localStorageKey = `upload_${key}`;  // 用于缓存上传进度

    // 获取本地缓存的上传状态
    const uploadState = JSON.parse(localStorage.getItem(localStorageKey) || '{}');
    const uploadedChunks = uploadState.uploadedChunks || [];  // 已上传的分片
    const etags = uploadState.etags || [];  // 已上传分片的ETag

    // 计算已上传的文件大小
    let totalUploaded = uploadedChunks.reduce((acc, partNumber) => {
        const chunk = chunks.value[partNumber - 1]; // 获取已上传的分片
        return acc + chunk.size;
    }, 0);

    // 计算上传进度并保留两位小数
    progress.value = parseFloat(((totalUploaded / file.value.size) * 100).toFixed(2));

    try {
        // 如果没有UploadId，先创建Multipart上传任务
        let uploadId = uploadState.uploadId;
        if (!uploadId) {
            const params = {
                Bucket: bucket,
                Key: key,
                ContentType: file.value.type
            };
            const data = await s3Client.send(new CreateMultipartUploadCommand(params));
            uploadId = data.UploadId;  // 获取并保存上传ID

            // 存储上传任务状态
            localStorage.setItem(localStorageKey, JSON.stringify({
                uploadId,
                uploadedChunks,
                etags
            }));
        }

        // 从已上传的分片继续上传
        for (let i = uploadedChunks.length; i < chunks.value.length; i++) {
            const partNumber = i + 1;
            const chunk = chunks.value[i];

            // 上传分片
            const response = await s3Client.send(new UploadPartCommand({
                Bucket: bucket,
                Key: key,
                UploadId: uploadId,
                PartNumber: partNumber,
                Body: chunk
            }));

            console.log(response);
            console.log(response.ETag);

            // 更新ETag和已上传的部分
            etags.push(response.ETag);
            uploadedChunks.push(partNumber);

            // 更新本地缓存
            localStorage.setItem(localStorageKey, JSON.stringify({
                uploadId,
                uploadedChunks,
                etags
            }));

            // 更新上传进度，并保留两位小数
            totalUploaded += chunk.size;
            progress.value = parseFloat(((totalUploaded / file.value.size) * 100).toFixed(2));
        }

        // 上传完成，合并分片
        await s3Client.send(new CompleteMultipartUploadCommand({
            Bucket: bucket,
            Key: key,
            UploadId: uploadId,
            MultipartUpload: {
                Parts: uploadedChunks.map((partNumber, index) => ({
                    ETag: etags[index],
                    PartNumber: partNumber
                }))
            }
        }));

        fileUrl.value = `http://api.oss.boadan.com/${bucket}/${key}`;
        uploadMessage.value = '文件上传成功';

        // 上传完成后清除本地缓存
        localStorage.removeItem(localStorageKey);
    } catch (error) {
        uploadMessage.value = '文件上传失败';
        console.error(error);
    } finally {
        isUploading.value = false;
    }
};

onMounted(() => {
})
</script>